package model.Utils;

import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import model.FileVO;
import model.GenericTreeNode;
import model.Vertex3f;

public class RingHelper {
	
	private static HashMap<List<GenericTreeNode<FileVO>>, ArrayList<ArrayList<Vertex3f>>> cache = new HashMap<List<GenericTreeNode<FileVO>>, ArrayList<ArrayList<Vertex3f>>>();
	
	public static List<Vertex3f> getRingCentersList(List<GenericTreeNode<FileVO>> files) {
		if (files == null || files.size() == 0) {
			throw new InvalidParameterException("Nie ustawiono childElements!");
		}
		if (files.get(0).getData().getParentCircleCenter() == null) {
			throw new InvalidParameterException("Nie wywolano FilesPlacer.placeFiles()!");
		}
		
		List<Vertex3f> l = new ArrayList<Vertex3f>();
		l.add(files.get(0).getData().getParentCircleCenter());
		for (int i = 0; i < files.size(); ++i) {
			if (!l.get(l.size() - 1).equals(files.get(i).getData().getParentCircleCenter())) {
				l.add(files.get(i).getData().getParentCircleCenter());
			}			
		}
		
		return l;
	}
	
	private static ArrayList<ArrayList<Vertex3f>> cached(List<GenericTreeNode<FileVO>> key) {	
		return cache.get(key);
	}
	
	
	public static ArrayList<ArrayList<Vertex3f>> getVerticesToConnectList(List<GenericTreeNode<FileVO>> files) {

		ArrayList<ArrayList<Vertex3f>> l = cached(files);
		
		if (l == null) {
			l = new ArrayList<ArrayList<Vertex3f>>();
			int numberOfRings = getRingCentersList(files).size();
			ArrayList<GenericTreeNode<FileVO>> mainRing = getRingNodesFromId(0, files);

			l.add(getConnectedRingVertices(mainRing));

			for (int i = 1; i < numberOfRings; ++i) {

				ArrayList<GenericTreeNode<FileVO>> currentRing = getRingNodesFromId(i, files);
				l.add(getConnectedRingVertices(currentRing));
				ArrayList<Vertex3f> vertexPair = getClosestPair(mainRing, currentRing);
				l.add(vertexPair);

			}
			cache.put(files, l);
		}
		
		return l;
	}	
	
	private static ArrayList<Vertex3f> getConnectedRingVertices(ArrayList<GenericTreeNode<FileVO>> l) {

		ArrayList<Vertex3f> result = new ArrayList<Vertex3f>();
		
		for (GenericTreeNode<FileVO> node : l) {
			result.add(getVertex3f(node));
		}
		//result.add(getVertex3f(l.get(0)));
		
		return result;
	}

	private static ArrayList<Vertex3f> getClosestPair(List<GenericTreeNode<FileVO>> l1, ArrayList<GenericTreeNode<FileVO>> l2) {
		
		float shortestDistance = Float.MAX_VALUE;
		
		ArrayList<Vertex3f> result = new ArrayList<Vertex3f>(2);
		for (GenericTreeNode<FileVO> node1 : l1) {
			for (GenericTreeNode<FileVO> node2 : l2) {
				float dist;
				if ((dist = getDistance(node1, node2)) < shortestDistance) {
					shortestDistance = dist;
					result.clear();
					result.add(getVertex3f(node1));
					result.add(getVertex3f(node2));
				}			
			}				
		}
		
		return result;
	}

	private static Vertex3f getVertex3f(GenericTreeNode<FileVO> node) {
		return new Vertex3f(node.getData().getPosX(), node.getData().getPosY(), node.getData().getPosZ(), node.getData().getRingId());
	}

	private static float getDistance(GenericTreeNode<FileVO> node1,	GenericTreeNode<FileVO> node2) {
		
		float xDiff = node1.getData().getPosX() - node2.getData().getPosX();
		float yDiff = node1.getData().getPosY() - node2.getData().getPosY();
		float zDiff = node1.getData().getPosZ() - node2.getData().getPosZ();
		
		xDiff *= xDiff;
		yDiff *= yDiff;
		zDiff *= zDiff;
			
		return (float) Math.sqrt(xDiff + yDiff + zDiff);
	}

	private static ArrayList<GenericTreeNode<FileVO>> getRingNodesFromId(int ringId, List<GenericTreeNode<FileVO>> files) {
		
		ArrayList<GenericTreeNode<FileVO>> l = new ArrayList<GenericTreeNode<FileVO>>();
		for (GenericTreeNode<FileVO> node : files) {
			
			if (node.getData().getRingId() == ringId) {
				l.add(node);
			}	
		}
		
		return l;
	}
}

